package com.yiyuan.app.service.impl;

import cn.hutool.core.date.LocalDateTimeUtil;
import com.guaike.core.entity.param.Page;
import com.guaike.core.entity.result.PageEntity;
import com.guaike.core.entity.result.Result;
import com.guaike.core.redis.context.ApiContext;
import com.guaike.core.utils.ListUtil;
import com.yiyuan.app.entity.enums.DetailsTypeEnum;
import com.yiyuan.app.entity.enums.LabelTypeEnum;
import com.yiyuan.app.entity.param.ModifyUserInfoDTO;
import com.yiyuan.app.entity.param.RedeemDTO;
import com.yiyuan.app.service.MineService;
import com.yiyuan.app.dao.*;
import com.yiyuan.app.entity.po.*;
import com.yiyuan.app.entity.result.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
@AllArgsConstructor
public class MineServiceImpl implements MineService {

    private final UAppUserDAO uAppUserDAO;
    private final UAppUserEquityDAO uAppUserEquityDAO;
    private final MConfVipDAO mConfVipDAO;
    private final MRecordPineDAO mRecordPineDAO;
    private final MRecordPineDetailDAO mRecordPineDetailDAO;
    private final DDetailsPineconeDAO dDetailsPineconeDAO;
    private final OArticleDAO oArticleDAO;
    private final MConfDescriptionDAO mConfDescriptionDAO;

    @Override
    public Result<MineVO> userInfo() {
        MineVO vo = new MineVO();
        AppUser currentUser = ApiContext.getCurrentUser();
        UAppUserPO userPO = uAppUserDAO.findById(currentUser.getUserId());
        UAppUserEquityPO equityPO = uAppUserEquityDAO.findOne(UAppUserEquityPO::getUserId, currentUser.getUserId());
        vo.setUserId(userPO.getId());
        vo.setNickname(userPO.getNickname());
        vo.setAvatarurl(userPO.getAvatarurl());
        vo.setMyVipLevel(equityPO.getVipGrade());
        vo.setMyRechargeMoney(equityPO.getRechargeMoney());
        vo.setPinecone(equityPO.getPinecone());
        vo.setPineNut(equityPO.getPineNut());
        MConfVipPO vipPO = mConfVipDAO.findOne(MConfVipPO::getVipLevel, equityPO.getVipGrade() + 1);
        if (Objects.nonNull(vipPO)) {
            vo.setNextThreshold(vipPO.getThreshold());
            vo.setGiveRate(vipPO.getGiveRate());
            vo.setNextVipLevel(vipPO.getVipLevel());
        }
        MConfVipPO myVipPO = mConfVipDAO.findOne(MConfVipPO::getVipLevel, equityPO.getVipGrade());
        if (Objects.nonNull(myVipPO)) {
            vo.setCurrentGiveRate(myVipPO.getGiveRate());
        }
        LocalDate now = LocalDate.now();
        LocalDate startOfWeek = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        LocalDate endOfWeek = now.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));

        LocalDate startOfLastWeek = startOfWeek.minusWeeks(1);
        LocalDate endOfLastWeek = endOfWeek.minusWeeks(1);
        MRecordPinePO weekPine = mRecordPineDAO.findUserPine(startOfLastWeek, endOfLastWeek, currentUser.getUserId());
        MRecordPinePO nextWeekPine = mRecordPineDAO.findUserPine(startOfWeek, endOfWeek, currentUser.getUserId());
        if (Objects.nonNull(weekPine)) {
            vo.setWeekPinecone(weekPine.getGetPinecone());
        }
        if (Objects.nonNull(nextWeekPine)) {
            vo.setNextWeekPinecone(nextWeekPine.getGetPinecone());
        }
        return Result.success().data(vo).build();
    }

    @Override
    public Result<MyPineDataVO> findMyPinecone() {
        MyPineDataVO vo = new MyPineDataVO();
        AppUser currentUser = ApiContext.getCurrentUser();
        UAppUserEquityPO equityPO = uAppUserEquityDAO.findOne(UAppUserEquityPO::getUserId, currentUser.getUserId());
        vo.setPinecone(equityPO.getPinecone());
        vo.setPineNut(equityPO.getPineNut());
        return Result.success().data(vo).build();
    }

    @Override
    public Result<PageEntity<PineRecordVO>> pineRecordPage(Page param) {
        AppUser currentUser = ApiContext.getCurrentUser();
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<MRecordPinePO> poPage = mRecordPineDAO.findPage(currentUser, param.getPageIndex(), param.getPageSize());
        LocalDate now = LocalDate.now();
        LocalDate startOfWeek = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        LocalDate startOfLastWeek = startOfWeek.minusWeeks(1);
        PageEntity<PineRecordVO> result = new PageEntity<>();
        List<PineRecordVO> list = new ArrayList<>();
        poPage.getRecords().forEach(po -> {
            PineRecordVO vo = new PineRecordVO();
            if (po.getStartDate().isEqual(startOfWeek)) {
                vo.setTitle("本周");
            } else if (po.getStartDate().isEqual(startOfLastWeek)) {
                vo.setTitle("上周");
            } else {
                String title = LocalDateTimeUtil.format(po.getStartDate(), "yyyy/MM/dd") + "-" + LocalDateTimeUtil.format(po.getEndDate(), "yyyy/MM/dd");
                vo.setTitle(title);
            }
            vo.setPinecone(po.getGetPinecone());
            List<MRecordPineDetailPO> pos = mRecordPineDetailDAO.findList(MRecordPineDetailPO::getRecordPineId, po.getId(), MRecordPineDetailPO::getId);
            List<BasePineVO> recordVOS = ListUtil.copyList(pos, BasePineVO.class);
            vo.setRecordVOS(recordVOS);
            list.add(vo);
        });
        result.setList(list);
        result.setTotal(poPage.getTotal());
        return Result.success().data(result).build();
    }

    @Override
    public Result<PineVO> pineInfo() {
        PineVO vo = new PineVO();
        AppUser currentUser = ApiContext.getCurrentUser();
        UAppUserEquityPO equityPO = uAppUserEquityDAO.findOne(UAppUserEquityPO::getUserId, currentUser.getUserId());
        vo.setPinecone(equityPO.getPinecone());
        LocalDate now = LocalDate.now();
        LocalDate startOfWeek = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        LocalDate endOfWeek = now.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));

        LocalDate startOfLastWeek = startOfWeek.minusWeeks(1);
        LocalDate endOfLastWeek = endOfWeek.minusWeeks(1);
        MRecordPinePO weekPine = mRecordPineDAO.findUserPine(startOfLastWeek, endOfLastWeek, currentUser.getUserId());
        if (Objects.nonNull(weekPine)) {
            vo.setReceivePinecone(weekPine.getGetPinecone());
            vo.setAlreadyReceive(weekPine.getIsGet());
        }
        return Result.success().data(vo).build();
    }

    @Override
    @Transactional
    public Result<Boolean> getPinePrize() {
        AppUser currentUser = ApiContext.getCurrentUser();
        LocalDate now = LocalDate.now();
        LocalDate startOfWeek = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        LocalDate endOfWeek = now.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));

        LocalDate startOfLastWeek = startOfWeek.minusWeeks(1);
        LocalDate endOfLastWeek = endOfWeek.minusWeeks(1);
        MRecordPinePO weekPine = mRecordPineDAO.findUserPine(startOfLastWeek, endOfLastWeek, currentUser.getUserId());
        if (Objects.isNull(weekPine)) {
            return Result.failure().message("你还没有可领取的松树").build();
        }
        if (weekPine.getIsGet()) {
            return Result.failure().message("本周松树已领取，不能重复领取").build();
        }
        weekPine.setIsGet(Boolean.TRUE);
        mRecordPineDAO.updateById(weekPine);
        DDetailsPineconePO po = new DDetailsPineconePO();
        po.setUserId(currentUser.getUserId());
        po.setLabelType(LabelTypeEnum.pine.getCode());
        po.setDetailsType(DetailsTypeEnum.income.getCode());
        po.setPinecone(weekPine.getGetPinecone());
        dDetailsPineconeDAO.save(po);
        uAppUserEquityDAO.addPinecone(currentUser.getUserId(), weekPine.getGetPinecone());
        return Result.success().data(Boolean.TRUE).build();
    }

    @Override
    public Result<RedeemPineconeVO> redeemPineconeInfo() {
        RedeemPineconeVO vo = new RedeemPineconeVO();
        AppUser currentUser = ApiContext.getCurrentUser();
        UAppUserEquityPO equityPO = uAppUserEquityDAO.findOne(UAppUserEquityPO::getUserId, currentUser.getUserId());
        MConfVipPO vipPO = mConfVipDAO.findOne(MConfVipPO::getVipLevel, equityPO.getVipGrade());
        vo.setPineNut(equityPO.getPineNut().longValue());
        vo.setRatio(vipPO.getExchangeRate());
        vo.setMaxPinecone(equityPO.getPineNut().longValue() * 10 / vipPO.getExchangeRate());
        return Result.success().data(vo).build();
    }

    @Override
    @Transactional
    public Result<Boolean> redeemPinecone(RedeemDTO param) {
        AppUser currentUser = ApiContext.getCurrentUser();
        UAppUserEquityPO equityPO = uAppUserEquityDAO.findOne(UAppUserEquityPO::getUserId, currentUser.getUserId());
        MConfVipPO vipPO = mConfVipDAO.findOne(MConfVipPO::getVipLevel, equityPO.getVipGrade());
        int pineNut = Math.multiplyExact(param.getPinecone(), vipPO.getExchangeRate()) / 10;
        if (pineNut > equityPO.getPineNut()) {
            return Result.failure().message("超过最大可兑换松果数").build();
        }
        uAppUserEquityDAO.updatePineNut(currentUser.getUserId(), -pineNut);
        DDetailsPineconePO po = new DDetailsPineconePO();
        po.setUserId(currentUser.getUserId());
        po.setLabelType(LabelTypeEnum.redemption.getCode());
        po.setDetailsType(DetailsTypeEnum.income.getCode());
        po.setPinecone(param.getPinecone());
        po.setRemark("兑换比例" + vipPO.getExchangeRate() + ":10");
        dDetailsPineconeDAO.save(po);
        uAppUserEquityDAO.addPinecone(currentUser.getUserId(), param.getPinecone());
        return Result.success().data(Boolean.TRUE).build();
    }

    @Override
    @Transactional
    public Result<Boolean> modifyNickName(ModifyUserInfoDTO param) {
        AppUser currentUser = ApiContext.getCurrentUser();
        Integer pinecone = 10000;
        UAppUserEquityPO equityPO = uAppUserEquityDAO.findOne(UAppUserEquityPO::getUserId, currentUser.getUserId());
        if (equityPO.getPinecone() < pinecone) {
            return Result.failure().message("您的松果余额不足，请充值").build();
        }
        UAppUserPO userPO = uAppUserDAO.findById(currentUser.getUserId());
        userPO.setNickname(param.getNickName());
        uAppUserDAO.updateById(userPO);
        uAppUserEquityDAO.addPinecone(currentUser.getUserId(), -pinecone);
        DDetailsPineconePO myDetail = new DDetailsPineconePO();
        myDetail.setUserId(currentUser.getUserId());
        myDetail.setLabelType(LabelTypeEnum.rename.getCode());
        myDetail.setDetailsType(DetailsTypeEnum.pay_out.getCode());
        myDetail.setPinecone(pinecone);
        dDetailsPineconeDAO.save(myDetail);
        return Result.success().data(Boolean.TRUE).build();
    }

    @Override
    public Result<List<ArticleVO>> articleInfo(Integer articleType) {
        List<ArticleVO> list = new ArrayList<>();
        List<OArticlePO> pos = oArticleDAO.findList(OArticlePO::getType, articleType);
        if (CollectionUtils.isEmpty(pos)) {
            return Result.success().data(list).build();
        }
        List<Long> ids = pos.stream().map(OArticlePO::getDescriptionId).collect(Collectors.toList());
        List<MConfDescriptionPO> descriptionPOS = mConfDescriptionDAO.findByIdList(ids);
        Map<Long, List<MConfDescriptionPO>> listMap = descriptionPOS.stream().collect(Collectors.groupingBy(MConfDescriptionPO::getId));
        pos.forEach(po -> {
            ArticleVO vo = new ArticleVO();
            vo.setTitle(po.getTitle());
            vo.setContent(listMap.get(po.getDescriptionId()).get(0).getContent());
            list.add(vo);
        });
        return Result.success().data(list).build();
    }

}
